/* 
* ip_lib.c
* 
* Copyright Anthony Lineberry 2007 
* 
* This file is copyright and licensed under the GNU GPL v2.0 
* 
*/ 

#include "ip.h"
#include "adapt.h"
#include "eth.h"
#include "common.h"

#include "icmp.h"
#include "tcp.h"
//#include "udp.h"

#define IPv4_VERSION_LEN 0x45

static uint16_t lastID = 0;

int strToIp( char* str )
{
	// we need to find each dot (there will always be only 3)
	int dotPos[3];
	
	// find them
	int i;
	for( i = 0; i < 3; i++ )
	{
		if( i == 0 )
		{
			dotPos[i] = find( str, '.', 0, strlen( str ) );
			if( dotPos[i] == -1 )
				return 0; // invalid string
		}
		else
		{
			dotPos[i] = find( str, '.', dotPos[i-1] + 1, strlen( str ) );
			if( dotPos[i] == -1 )
				return 0; // invalid string
		}
	}
	
	// we have dot positions
	
	// get each part of the ip
	char first[5];
	char second[5];
	char third[5];
	char fourth[5];
	
	// get them
	for( i = 0; i < dotPos[0]; i++ )
	{
		first[i] = str[i];
	}
	first[i] = 0;
	for( i = dotPos[0] + 1; i < dotPos[1]; i++ )
	{
		second[i-(dotPos[0] + 1)] = str[i];
	}
	second[i-(dotPos[0] + 1)] = 0;
	for( i = dotPos[1] + 1; i < dotPos[2]; i++ )
	{
		third[i-(dotPos[1] + 1)] = str[i];
	}
	third[i-(dotPos[1] + 1)] = 0;
	for( i = dotPos[2] + 1; i < strlen( str ); i++ )
	{
		fourth[i-(dotPos[2] + 1)] = str[i];
	}
	fourth[i-(dotPos[2] + 1)] = 0;
	
	// turn into integers
	int part1,part2,part3,part4;
	part1 = atoi( first );
	part2 = atoi( second );
	part3 = atoi( third );
	part4 = atoi( fourth );
	
	// return the IP
	return inetAddress( part1, part2, part3, part4 );
}

void *ipStripHeader(packet_t *p)
{
	return (void *)(((char *)p->data)+sizeof(ethHeader_t)+sizeof(ipHeader_t));
}

int ipSendPacket( ethernet_t *eth, int ipDest, packet_t *p, uint8_t type, int allchksum )
{
	// get an adapter to work with
	netAdapter_t *nic;
	if( !eth || !eth->adapter )
		return;
	nic = eth->adapter;

	// create the IP header
	packet_t *pkt = packetAddHeader(sizeof(ipHeader_t), p);
	ipHeader_t *ip = (ipHeader_t *) (pkt->data);
	ip->verlen = IPv4_VERSION_LEN;
	ip->tos = 0;
	ip->len = htons(pkt->len);

	lastID++;

	ip->id = htons(lastID);
	ip->frag = htons(0);
	ip->ttl = 128;
	ip->type = type;
	ip->checksum = 0;
	ip->ipSrc = nic->ipaddr;
	ip->ipDest = ipDest;
		
		
	if( allchksum )
	{
		ip->checksum = packetChecksum( pkt, pkt->len );
	}
	else
	{
		ip->checksum = packetChecksum( pkt, sizeof(ipHeader_t) );
	}

	return sendPacketEthernet(eth, pkt);
}

void handleIpPacket(ethernet_t *eth, packet_t *pkt)
{
	int hlen;
	int iplen;

	ipHeader_t *ipPkt = (ipHeader_t *)ethernetStripHeader(pkt);
	
	hlen = (ipPkt->verlen & 0x0f) * 4;
	iplen = ntohs(ipPkt->len);

	switch(ipPkt->type)
	{
		case IP_TYPE_ICMP:
			printf( "ICMP Packet\n" );
			handleIcmpPacket(eth, pkt);
			break;
		case IP_TYPE_TCP:
			printf( "TCP Packet\n" );
			handleTCPpacket( eth, pkt ); 
			break;
		case IP_TYPE_UDP:
			printf( "TODO: UDP Packet\n" );
			
			//handleUDPpacket( eth, pkt ); 
			break;
		default:
			printf( "Unknown IP packet type\n" );
			break;
	}
}